/*
 * UtilAsistente.java
 *
 * Copyright 2011 Universidad Francisco de Paula Santander (UFPS).
 * Todos los Derechos Reservados.
 * Creado el 16/06/2010, 06:55:38 AM
 */
package com.ufps.cuatro.modelo.asistente;

import java.awt.GridBagConstraints;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JTree;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import com.ufps.cuatro.modelo.representacion.componente.Componente;
import com.ufps.cuatro.modelo.representacion.componente.ComponenteDistribuidor;
import com.ufps.cuatro.modelo.representacion.ObjetoTipoDatoReflexion;
import com.ufps.cuatro.modelo.representacion.Propiedad;
import com.ufps.cuatro.modelo.representacion.UtilRepresentacion;
import com.ufps.cuatro.util.TipoCaso;
import com.ufps.cuatro.util.Utileria;
import com.ufps.cuatro.util.UtileriaBase;
import com.ufps.cuatro.util.model.MyCheckItemPropertiesClass;
import com.ufps.cuatro.util.model.MyTableModelDistribucionGridBagConstraints;
import com.ufps.cuatro.util.model.MyTableModelProperties;
import com.ufps.cuatro.util.model.MyTableModelPropertiesClass;
import com.ufps.cuatro.util.opciones.MyProperties;


/**
 * <i><b>UtilAsistente:</b></i><p>Esta clase abstracta es la encargada de implementar
 * los métodos utilitarios de soporte del paquete de asistentes.</p>
 * 
 * @author Carlos A. Torres C. - Dolly E. Guerrero. <https://code.google.com/p/tesis4dor/>
 * @version 1.0 16/06/2010
 * @see UtileriaBase
 */
public abstract class UtilAsistente extends UtileriaBase{    
    /**
     * Identifica la Representación del Clases por Constructor por medio de Asistentes.
     */
    public final static int REPRESENTACION_CLASE_CONSTRUCTOR = 0;   
    /**
     * Identifica la Representación del Clases por Métodos de Entrada por medio de Asistentes.
     */
    public final static int REPRESENTACION_CLASE_ENTRADA = 1;
    /**
     * Identifica la Representación del Clases por Métodos de Salida por medio de Asistentes.
     */
    public final static int REPRESENTACION_CLASE_SALIDA = 2;    
    
    /**
     * Contiene el Maximo de Filas para Visualizar las Propiedades de un
     * <code>GridBagConstraints</code> en un <code>JTable</code>.
     */
    public final static int SIZE_PROPERTIES_GRIDBAGCONSTRAINTS = 14;       
    /**
     * Variable static para almacenar los Recursos en las Subclases.
     */
    public static org.jdesktop.application.ResourceMap resourceMap;

    static{
        try{
            resourceMap = org.jdesktop.application.Application.getInstance(com.ufps.cuatro.CuatroApp.class).getContext().getResourceMap(UtilAsistente.class);        
        }catch(java.lang.Exception ex){}        
    }
    
    /**
     * Devuelve el Recurso de Texto Asociado a la Clave recibida en el Parametro ó
     * un Cadena vacia en Caso de no encontrarse ó presentarse un Error.
     * @param key Clave recibida.
     * @return Recurso de Texto Asociado a la Clave recibida en el Parametro.
     * @see org.jdesktop.application.ResourceMap#getString(java.lang.String, java.lang.Object[]) 
     * @throws ResourceMap.LookupException
     * @throws java.lang.IllegalArgumentException
     */
    public static String leerRecursoTexto(String key){
        try{
            if(resourceMap.containsKey(key)){
                return resourceMap.getString(key);
            }
        }catch(java.lang.NullPointerException ex){}
        return "";
    }

    /**
     * Devuelve el Icono de la Aplicación de acuerdo  al tamaño recibido en el Parametro.
     * @param modo 
     * @return Icono de la Aplicación de acuerdo  al tamaño recibido en el Parametro.
     * @see org.jdesktop.application.ResourceMap#getIcon(java.lang.String) 
     * @throws ResourceMap.LookupException
     * @throws java.lang.IllegalArgumentException
     */
    public static Icon leerIconoApp(int modo){
       try{
            String key = "Utileria.icono.app." + String.valueOf(modo);
            return resourceMap.getIcon(key);
        }catch(java.lang.NullPointerException ex){}
       return null;
    }

    /**
     * Devuelve el Icono de la Aplicación en Formato Imagen de acuerdo  al tamaño recibido en el Parametro.
     * @param modo 
     * @return Icono de la Aplicación en Formato Imagen de acuerdo  al tamaño recibido en el Parametro.
     * @see org.jdesktop.application.ResourceMap#getIcon(java.lang.String) 
     * @throws ResourceMap.LookupException
     * @throws java.lang.IllegalArgumentException
     */
    public static ImageIcon leerIconoAppEnImagen(int modo){
        try{
            String key = "Utileria.icono.app." + String.valueOf(modo);
            return resourceMap.getImageIcon(key);
        }catch(java.lang.NullPointerException ex){}
        return null;
    }    
    
    /**
     * Devuelve el Recurso de Gráfico de Icono Asociado a la Clave y al Tamaño recibidos 
     * en los Parametros.
     * @param key Clave recibida.
     * @param size Tamaño del Icono.
     * @return Recurso de Gráfico de Icono Asociado a la Clave y al Tamaño recibidos 
     * en los Parametros.
     * @see org.jdesktop.application.ResourceMap#getIcon(java.lang.String) 
     * @throws ResourceMap.LookupException
     * @throws java.lang.IllegalArgumentException
     */
    public static Icon leerRecursoIcono(String key, int size){
        try{
            String strPath = null;
            if(size == 16){
                strPath = key.replaceAll("32x32", "16x16");
            }
            else if(size == 32){
                strPath = key.replaceAll("16x16", "32x32");
            }    
            strPath += UtileriaBase.leerRecursoTexto(key);
            return resourceMap.getIcon(strPath);        
        } catch(java.lang.NullPointerException ex){}
        return null;
    }   
    
    /**
     * Devuelve el Recurso de Gráfico de Imagen Asociado a la Clave y al Tamaño recibidos 
     * en los Parametros.
     * @param key Clave recibida.
     * @param size Tamaño de la Imagen.
     * @return Recurso de Gráfico de Imagen Asociado a la Clave y al Tamaño recibidos 
     * en los Parametros.
     * @see org.jdesktop.application.ResourceMap#getIcon(java.lang.String) 
     * @throws ResourceMap.LookupException
     * @throws java.lang.IllegalArgumentException
     */
    public static ImageIcon leerRecursoImagen(String key, int size){        
       try{ 
            String strPath = "";
            if(size == UtileriaBase.SIZE_ICON_16){
                strPath = key.replaceAll("32x32", "16x16");
            }
            else if(size == UtileriaBase.SIZE_ICON_32){
                strPath = key.replaceAll("16x16", "32x32");
            }        
            return resourceMap.getImageIcon(strPath);
        }catch(java.lang.NullPointerException ex){}
       return null;
    }
    
    /**
     * Carga un Archivo Properties en el formato válido de la Aplicación
     * para la administración de este tipo de archivo.
     * @param strPath Ruta de la Ubicación del Recurso.
     * @return Archivo Properties ecansulado en un objeto <code>MyProperties</code>.
     */
    public static MyProperties cargar(String strPath){
       try{ 
            URL url = resourceMap.getClassLoader().getResource(strPath);
            try {
                MyProperties objPropiedades = new MyProperties(url.toURI());
                return objPropiedades;
            } catch (IOException ex) {
                Logger.getLogger(UtileriaBase.class.getName()).log(Level.SEVERE, null, ex);
            } catch (URISyntaxException ex) {
                Logger.getLogger(UtileriaBase.class.getName()).log(Level.SEVERE, null, ex);
            }
            return null;
        }  catch(java.lang.NullPointerException ex){}
       return null;
    }     
    
    /**
     * Carga un Archivo Properties en el formato válido de la Aplicación
     * para la administración de este tipo de archivo.
     * @param objPath Ruta de la Ubicación del Recurso.
     * @return Archivo Properties ecansulado en un objeto <code>MyProperties</code>.
     */
    public static MyProperties cargarFileProperties(File objPath){
       try{
        try {            
            MyProperties objPropiedades = new MyProperties(objPath.toURI());
            return objPropiedades;
        } catch (IOException ex) {
            Logger.getLogger(Utileria.class.getName()).log(Level.SEVERE, null, ex);
        } 
         }catch(java.lang.NullPointerException ex){}
        return null;      
    }
    
    /**
     * Crea y Devuelve la Tabla de Propiedades Disponibles incluidas en la Colección recibida.
     * @param objPropiedadesDisponibles Colección de Propiedades Disponibles.
     * @return Tabla de Propiedades Disponibles incluidas en la Colección recibida.
     */
    public static MyTableModelProperties crearTablaPropiedadesDisponibles(List<Propiedad> objPropiedadesDisponibles){
        try{
            int size = objPropiedadesDisponibles.size();
            String[] titulos = {MyTableModelProperties.NAME_COLUMN_ALIAS, 
                MyTableModelProperties.NAME_COLUMN_VALUES, 
                MyTableModelProperties.NAME_COLUMN_VIEWSET, 
                MyTableModelProperties.NAME_COLUMN_VIEWGET
            };
            Object[][] datos = new Object[size][5];
            for(int i = 0; i < size; i++){
                Propiedad objPropiedadDisponible = objPropiedadesDisponibles.get(i);
                datos[i][0] = objPropiedadDisponible.getAlias();
                datos[i][1] = objPropiedadDisponible;
                datos[i][2] = objPropiedadDisponible;
                datos[i][3] = objPropiedadDisponible;
            }
            return new MyTableModelProperties(titulos, datos);
        }catch(java.lang.NullPointerException ex){}
        return null;
    }
    
    /**
     * Crea y Devuelve la Tabla de Propiedades Internas incluidas en la Colección recibida.
     * @param objPropiedadesInternas Colección de Propiedades Internas.
     * @return Tabla de Propiedades Internas incluidas en la Colección recibida.
     */
    public static MyTableModelProperties crearTablaPropiedadesInternas(List<Propiedad> objPropiedadesInternas){
        try{
            int size = objPropiedadesInternas.size();
            String[] titulos = {MyTableModelProperties.NAME_COLUMN_ALIAS,             
                MyTableModelProperties.NAME_COLUMN_VIEWSET, 
                MyTableModelProperties.NAME_COLUMN_VIEWGET};
            Object[][] datos = new Object[size][3];
            for(int i = 0; i < size; i++){
                Propiedad objPropiedadInterna = objPropiedadesInternas.get(i);
                datos[i][0] = objPropiedadInterna.getAlias();
                datos[i][1] = objPropiedadInterna;
                datos[i][2] = objPropiedadInterna;
            }
            return new MyTableModelProperties(titulos, datos);
        }catch(java.lang.NullPointerException ex){}
        return null;
    }
    
    /**
     * Crea y Devuelve la Tabla de Atributos de la Clase.
     * @param objTipoDato Tipo de Dato que representa una clase del Modelo analizado(jar)
     * @return Tabla de Atributos de la Clase.
     */
    public static MyTableModelPropertiesClass crearTablaPropiedadesAtributosClase(ObjetoTipoDatoReflexion objTipoDato){
       try{ 
        String strClassPath = objTipoDato.getStrClassPath();
        Class<?> objClass = null;
        //Se comprueba que objeto la clase este registrada
        if(objTipoDato.getObjClass() != null){
            objClass = objTipoDato.getObjClass();
        }
        else{                
            try {
                objClass = Class.forName(strClassPath);
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(UtilAsistente.class.getName()).log(Level.SEVERE, null, ex);
            }
            return null;
        }
        
        //se extraen las propiedades;    
        Field[] objTempPropiedades = objClass.getFields();
        List<Field> ListFields = Arrays.asList(objTempPropiedades);
        ArrayList<MyCheckItemPropertiesClass> objAtributos = new ArrayList<MyCheckItemPropertiesClass>();        

        for(Field objField : ListFields){
            MyCheckItemPropertiesClass objItem = new MyCheckItemPropertiesClass(objField);
            if(objTipoDato.getObjCaso().geteCaso() == TipoCaso.eJDKNoRegistrado){
                Class<?> objClassTipoDato = objField.getType();
                if(UtilRepresentacion.isExisteTipoDato(objClassTipoDato)){
                    objAtributos.add(objItem);
                }
            }
            else{
                objAtributos.add(objItem);
            }
        }
        
        int size = objAtributos.size();
        String[] titulos = {MyTableModelProperties.NAME_COLUMN_ALIAS, MyTableModelPropertiesClass.NAME_COLUMN_AGREGADO};
        Object[][] datos = new Object[size][3];
        for(int i = 0; i < size; i++){
            MyCheckItemPropertiesClass objItem = objAtributos.get(i);
            datos[i][0] = objItem;
            datos[i][1] = objItem;
        }
        MyTableModelPropertiesClass obj = new MyTableModelPropertiesClass(titulos, datos);        
        return obj;
    }catch(java.lang.NullPointerException ex){}
       return null;
    }
    
    /**
     * Crea y Devuelve la Tabla de Métodos de la Clase.
     * @param objTipoDato Tipo de Dato que representa una clase del Modelo analizado(jar)
     * @param modo Modo de devolución de Métodos (get/set)
     * @return Tabla de Métodos de la Clase.
     */
    public static MyTableModelPropertiesClass crearTablaPropiedadesMetodoClase(ObjetoTipoDatoReflexion objTipoDato, int modo){
      try{  
        String strClassPath = objTipoDato.getStrClassPath();
        Class<?> objClass = null;
        //Se comprueba que objeto la clase este registrada
        if(objTipoDato.getObjClass() != null){
            objClass = objTipoDato.getObjClass();
        }
        else{                
            try {
                objClass = Class.forName(strClassPath);
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(UtilAsistente.class.getName()).log(Level.SEVERE, null, ex);
            }
            return null;
        }
        
        //se extraen las propiedades;            
        Method[] objTempMetodos = objClass.getMethods();  
        List<Method> ListMethods = Arrays.asList(objTempMetodos);
        ArrayList<MyCheckItemPropertiesClass> objMetodos = new ArrayList<MyCheckItemPropertiesClass>();
            
        for(Method objMethod : ListMethods){
            switch(modo){
                case MyTableModelPropertiesClass.MODO_PROPIEDADES_SETGET:
                    if((UtilRepresentacion.isGetter(objMethod) || UtilRepresentacion.isIs(objMethod)) && !UtilRepresentacion.isMetodoExcluido(objMethod)){
                        MyCheckItemPropertiesClass objItem = new MyCheckItemPropertiesClass(objMethod);
                        if(objTipoDato.getObjCaso().geteCaso() == TipoCaso.eJDKNoRegistrado){
                            Class<?> objClassTipoDato = objMethod.getReturnType();
                            if(UtilRepresentacion.isExisteTipoDato(objClassTipoDato)){
                                objMetodos.add(objItem);
                            }
                        }
                        else{
                            objMetodos.add(objItem);
                        }
                    }
                    else if(UtilRepresentacion.isSetter(objMethod) && !UtilRepresentacion.isMetodoExcluido(objMethod)){
                        MyCheckItemPropertiesClass objItem = new MyCheckItemPropertiesClass(objMethod);
                        if(objTipoDato.getObjCaso().geteCaso() == TipoCaso.eJDKNoRegistrado){
                            Class<?> objClassTipoDato = objMethod.getParameterTypes()[0];
                            if(UtilRepresentacion.isExisteTipoDato(objClassTipoDato)){
                                objMetodos.add(objItem);
                            }
                        }
                        else{
                            objMetodos.add(objItem);
                        }
                    }
                    break;                
                case MyTableModelPropertiesClass.MODO_PROPIEDADES_NOTSETGET:
                    
                    if(!UtilRepresentacion.isGetter(objMethod) && 
                            !UtilRepresentacion.isIs(objMethod) && 
                            !UtilRepresentacion.isSetter(objMethod) &&
                            !UtilRepresentacion.isMetodoExcluido(objMethod)){
                        MyCheckItemPropertiesClass objItem = new MyCheckItemPropertiesClass(objMethod);
                        if(objTipoDato.getObjCaso().geteCaso() == TipoCaso.eJDKNoRegistrado){
                            Class<?> objClassTipoDato = objMethod.getReturnType();
                            if(UtilRepresentacion.isExisteTipoDato(objClassTipoDato)){
                                objMetodos.add(objItem);
                            }
                        }
                        else{
                            objMetodos.add(objItem);
                        }
                    }
                    break;
            }
        }
        int size = objMetodos.size();
        String[] titulos = {MyTableModelProperties.NAME_COLUMN_ALIAS, MyTableModelPropertiesClass.NAME_COLUMN_AGREGADO};
        Object[][] datos = new Object[size][3];
        for(int i = 0; i < size; i++){
            MyCheckItemPropertiesClass objItem = objMetodos.get(i);
            datos[i][0] = objItem;
            datos[i][1] = objItem;
        }
        MyTableModelPropertiesClass obj = new MyTableModelPropertiesClass(titulos, datos);        
        return obj;
    }catch(java.lang.NullPointerException ex){}
      return null;
    }
    
    /**
     * Crea y devuelve la Tabla que representa el GridBagContraints del Componente.
     * @param objComponente Componente que generará la Tabla.
     * @return Tabla que representa el GridBagContraints del Componente.
     */
    public static MyTableModelDistribucionGridBagConstraints crearTablaPropiedadesDistribucionComponente(Componente objComponente){
       try{
        int size = SIZE_PROPERTIES_GRIDBAGCONSTRAINTS;
        String[] titulos = {MyTableModelProperties.NAME_COLUMN_ALIAS, MyTableModelProperties.NAME_COLUMN_VALUES};
        Object[][] datos = new Object[size][2];        
        
        try{
            int i = 0;       
            GridBagConstraints objGridBagConstraints = objComponente.getGridBagConstraintsActiva();//getObjPlantillaComponenteSeleccionada().getObjGridBagConstraints();        
            asigTableDistribucion(objComponente, datos, i++, "gridx", objGridBagConstraints.gridx, false);
            asigTableDistribucion(objComponente, datos, i++, "gridy", objGridBagConstraints.gridy, false);
            asigTableDistribucion(objComponente, datos, i++, "gridwidth", objGridBagConstraints.gridwidth, true);
            asigTableDistribucion(objComponente, datos, i++, "gridheight", objGridBagConstraints.gridheight, true);
            asigTableDistribucion(objComponente, datos, i++, "weightx", objGridBagConstraints.weightx, true);
            asigTableDistribucion(objComponente, datos, i++, "weighty", objGridBagConstraints.weighty, true);
            asigTableDistribucion(objComponente, datos, i++, "ipadx", objGridBagConstraints.ipadx, true);
            asigTableDistribucion(objComponente, datos, i++, "ipady", objGridBagConstraints.ipady, true);
            asigTableDistribucion(objComponente, datos, i++, "anchor", objGridBagConstraints.anchor, true);
            asigTableDistribucion(objComponente, datos, i++, "fill", objGridBagConstraints.fill, true);
            asigTableDistribucion(objComponente, datos, i++, "insets.top", objGridBagConstraints.insets.top, true);
            asigTableDistribucion(objComponente, datos, i++, "insets.left", objGridBagConstraints.insets.left, true);
            asigTableDistribucion(objComponente, datos, i++, "insets.bottom", objGridBagConstraints.insets.bottom, true);
            asigTableDistribucion(objComponente, datos, i++, "insets.right", objGridBagConstraints.insets.right, true);
        }catch(java.lang.NullPointerException ex){
            datos = new Object[0][2];        
        }        
        return new MyTableModelDistribucionGridBagConstraints(titulos, datos);
    }catch(java.lang.NullPointerException ex){}
       return null;
    }
    
    private static void asigTableDistribucion(Componente objComponente, Object[][] datos, int i, String strName, Object objValue, boolean editable){
        ContenedorRegistroTabla objRegistro =
                new ContenedorRegistroTabla(objComponente, strName, i, objValue, editable);
        datos[i][0] = objRegistro.getStrNombreFila();
        datos[i][1] = objRegistro;
    }



    /**
     * Procesa, Formatea y devuelve una Cadena de Texto.
     * @param valor cadena de Texto que se analizará.
     * @param obj Objeto al que Aplica.
     * @return Cadena formateada.
     * @deprecated Método obsoleto cambio de implementación.
     */
    public static String procesarInicializacion(String valor, Object obj){        
        try{
        try{
            if(valor.indexOf("[idx]") > -1){
                return valor.replaceFirst("[idx]", String.valueOf(obj));
            }
            return valor;
        }catch(java.lang.Exception ex){
        }
        return "No Identificado";
    }catch(java.lang.NullPointerException ex){}
        return "";
    }
    
    /**
     * Expande todos los Nodos de un Arbol asociados a un Componente distribuidor.
     * @param tree Arbol.
     * @param objComponenteDistribuidor Componente desde el cual se expandirán los nodos.
     */
    public static void expandAll ( JTree tree, ComponenteDistribuidor objComponenteDistribuidor ) {
       try{ 
            TreeNode root = ( TreeNode ) tree.getModel () .getRoot () ;
            expandAll ( tree, new TreePath ( root ), objComponenteDistribuidor) ;
        }catch(java.lang.NullPointerException ex){}
       
    }
    
    private static void expandAll ( JTree tree, TreePath parent, ComponenteDistribuidor objComponenteDistribuidor ) {
        TreeNode node = ( TreeNode ) parent.getLastPathComponent () ;
        if ( node.getChildCount () >= 0 ) {
            for ( Enumeration e = node.children () ; e.hasMoreElements () ; ) {
                TreeNode n = ( TreeNode ) e.nextElement () ;
                TreePath path = parent.pathByAddingChild ( n ) ;
                expandAll ( tree, path, objComponenteDistribuidor ) ;
            }
        }
        tree.expandPath ( parent );
    }
}